﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Newtonsoft.Json;
using GJLib.inernal;

namespace GJLib
{
    public class BigSixNineHelper
    {

        JachiHelper jachiHelper = new JachiHelper();
        GanJiHelper ganjiHelper = new GanJiHelper();

        Dictionary<String, bool> _jiDayNight = null;

        List<String> _天將 = null;

        protected String loadContentFromFile(String fileName)
        {
            if (fileName.EndsWith(".json") == false)
                fileName += ".json";
            fileName = @"D:\project\五術\data\relation\" + fileName;
            String content = File.ReadAllText(fileName, Encoding.UTF8);
            return content;
        }
        protected void LoadGweiRen()
        {
            String content = loadContentFromFile("GweiRen");
            _天將 = JsonConvert.DeserializeObject<List<String>>(content);
        }
    
        protected void loadDaynight()
        {
            String fileName = @"D:\project\五術\data\relation" + "\\" + "jiDayNight.json";
            String content = File.ReadAllText(fileName, Encoding.UTF8);
            _jiDayNight = JsonConvert.DeserializeObject<Dictionary<String, bool>>(content);
        }
        public BigSixNineHelper()
        {
            loadDaynight();            
            LoadGweiRen();
        }
        protected bool isDay(String ji)
        {
            if (ji.Length > 1)
                ji = ji.Substring(1, 1);
            return _jiDayNight[ji];
        }

        public BigSixNinePan preparePan(DateTime dt, String 本命,bool male)
        {
            BigSixNinePan o= preparePan(dt);
            String 行年=GJR.行年(本命, o.占課四柱.yearGj.干支, male);
            o.options.Add("行年", 行年);
            return o;
        }
        public BigSixNinePan preparePan(DateTime dt)
        {
            Pillar4 起課時間 = new Pillar4();
            List<String> p4 = GanJiHelper.get4Pillar(dt);
            起課時間.datetime = dt;
            起課時間.setGj(p4);
            String monthGeneral = JachiHelper.getMonthGeneral(dt);
            List<Dictionary<String, String>> pan = new List<Dictionary<String, String>>();
            String[] jis = GanJiHelper.getJis();
            for (int i = 0; i < 12; i++)
            {
                Dictionary<string, string> d = new Dictionary<string, string>();
                d.Add("地", jis[i]);
                pan.Add(d);
            }
            prepareSkyPan(起課時間, monthGeneral, pan);


            BigSixNinePan pan69 = new BigSixNinePan();
            prepareSkyGeneral(起課時間, pan, pan69.options);
            List<String> class4 = prepare4Class(起課時間, pan);
            
            pan69.日期 = dt;
            pan69.setPillar(起課時間);
            pan69.setPan(pan);
            pan69.setClass4(class4);
            pan69.月將 = monthGeneral;
            preparePhase3(pan69);
            postprocessPhase3(pan69);
            prepareOtherOption(起課時間.yearGj.干支,
                                                   起課時間.monthGj.干支,
                                                   起課時間.dayGj.干支,
                                                   起課時間.hourGj.干支,
                                                   pan69.options);
            return pan69;
        }
        //其他條件..
        private void prepareOtherOption(String 年干支, String 月干支, String 日干支, String 時干支, Dictionary<String, Object> result)
        {
            bool isday = isDay(時干支);
            if (isday)
                result.Add("占法", "晝占");
            else
                result.Add("占法", "夜占");


            result.Add("旬首", GJR.旬首(日干支));
            result.Add("旬丁", GJR.旬丁(日干支));
            result.Add("旬庚", GJR.旬庚(日干支));
            result.Add("旬辛", GJR.旬辛(日干支));
            result.Add("旬癸", GJR.旬癸(日干支));
            result.Add("六合", GJR.六合(日干支));
            result.Add("支沖", GJR.沖(日干支));
            result.Add("日德", GJR.日德(日干支));
            result.Add("支德", GJR.支德(日干支));
            result.Add("天馬", GJR.天馬(日干支));
            result.Add("驛馬", GJR.驛馬(日干支));
            result.Add("桃花", GJR.桃花(日干支));
            result.Add("支刑", GJR.A刑B(日干支));
            result.Add("支破", GJR.支破(日干支));
            result.Add("支害", GJR.支害(日干支));

            result.Add("日空", GJR.空亡(日干支));
            result.Add("時空", GJR.空亡(時干支));
            result.Add("三合", GJR.三合(日干支));
            result.Add("月德", GJR.月德(月干支));

        }

        public String process遁干(String 干支, String 支神, out bool 空亡)
        {
            int diff = GJR.JiId(干支.Substring(1, 1)) - GJR.ganId(干支.Substring(0, 1));
            if (diff < 0)
                diff += 12;
            int id = GJR.JiId(支神);
            int ganid = (id - diff + 12) % 12;
            String 干神 = GJR.Id2Gan(ganid);
            if ((id == diff) || (id == (diff + 11) % 12))
            {
                空亡 = true;
            }
            空亡 = false;
            return 干神;
        }
        protected void process遁干(BigSixNinePan pan69)
        {
            String 日柱 = pan69.日干 + pan69.日支;

            bool 空亡 = false;
            foreach (var 傳 in pan69.三傳.Values)
            {
                傳.遁干 = process遁干(日柱, 傳.支神, out 空亡);
                if (空亡)
                    傳.空亡 = true;

            }
        }
        private void postprocessPhase3(BigSixNinePan pan69)
        {
            String 日干 = pan69.日干;
            foreach (var 傳 in pan69.三傳.Values)
            {
                傳.天將 = pan69.天盤(傳.支神).天將;
                傳.六親 = GJR.六親AofB(傳.支神, 日干);
            }
            process遁干(pan69);
        }

        protected int check課數(BigSixNinePan pan69)
        {
            HashSet<String> allset = new HashSet<string>();
            String s1 = pan69.課[0].上神 + GJR.天干寄宮(pan69.課[0].下神);
            allset.Add(s1);
            allset.Add(pan69.課[1].柱);
            allset.Add(pan69.課[2].柱);
            allset.Add(pan69.課[3].柱);
            int sz = allset.Count;
            allset.Clear();
            return sz;
        }
        protected void preparePhase3(BigSixNinePan pan69)
        {

            List<int> 賊課 = new List<int>();
            List<int> 剋課 = new List<int>();
            int 賊剋數 = 0;
            for (int i = 0; i < 4; i++)
            {
                if (pan69.課[i].剋 == 賊剋.賊)
                    賊課.Add(i);
                if (pan69.課[i].剋 == 賊剋.剋)
                    剋課.Add(i);
            }
            賊剋數 = 賊課.Count + 剋課.Count;
            List<String> notes = new List<string>();
            if (pan69.伏吟)
            {
                process伏吟(pan69, notes);
                return;
            }
            if (pan69.返吟)
            {
                if (賊剋數 > 0)
                    process返吟有剋(pan69, 賊課, 剋課, notes);
                else
                    process返吟無剋(pan69, notes);
                return;
            }
            if (pan69.八專)
            {
                if (賊課.Count + 剋課.Count > 0)
                {
                    processBasic(pan69, 賊課, 剋課, notes, false);
                }
                //沒有上下時,用八專法..不用遙剋法
                process八專(pan69, notes);
                return;
            }

           
            if (賊剋數 > 0)
            {
                if (pan69.不備)
                {
                    
                }                
                processBasic(pan69, 賊課, 剋課, notes, true);
                return;
            }
            if (process遙剋(pan69, notes))
                return;

            int 課數 = check課數(pan69);
            if (課數 == 4)
                process昂星(pan69, notes);


            if (課數 == 3)
                process別責(pan69, notes);

            throw new Exception("發現沒有法處理的!!");

        }

        private void process返吟有剋(BigSixNinePan pan69, List<int> 賊課, List<int> 剋課, List<string> notes)
        {
            notes.Add("返吟有剋-無依課");
            //這是錯的..
            processBasic(pan69, 賊課, 剋課, notes, false);
        }
        private void process返吟無剋(BigSixNinePan pan69, List<string> notes)
        {
            pan69.三傳["初傳"].支神 = GJR.驛馬(pan69.日支);
            pan69.三傳["中傳"].支神 = pan69.取上神(pan69.日支);
            pan69.三傳["末傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
            notes.Add("返吟無剋-無親課-井欄格");
        }

        private void process伏吟(BigSixNinePan pan69, List<string> notes)
        {
            String 日干 = pan69.日干;
            if (日干.Equals("癸"))
            {
                pan69.三傳["初傳"].支神 = "丑";
                pan69.三傳["中傳"].支神 = "戌";
                pan69.三傳["末傳"].支神 = "未";
                return;
            }
            if (日干.Equals("乙"))
            {
                pan69.三傳["初傳"].支神 = "辰";
                pan69.三傳["中傳"].支神 = pan69.日支;
                String next = GJR.A刑B(pan69.日支);
                if (next.Equals(pan69.三傳["中傳"].支神) || next.Equals(pan69.三傳["初傳"].支神))
                    next = GJR.沖(pan69.三傳["中傳"].支神);
                pan69.三傳["末傳"].支神 = next;
                return;
            }
            bool 陽日 = GJR.陰陽(日干) == e陰陽.陽;
            if (陽日)
            {
                pan69.三傳["初傳"].支神 = pan69.取上神(GJR.天干寄宮(日干));
                String next = GJR.A刑B(pan69.三傳["初傳"].支神);
                if (next.Equals(pan69.三傳["初傳"].支神))
                {
                    next = pan69.日支;
                }
                pan69.三傳["中傳"].支神 = next;
                next = GJR.A刑B(next);
                if (next.Equals(pan69.三傳["中傳"].支神) || next.Equals(pan69.三傳["初傳"].支神))
                    next = GJR.沖(next);
                pan69.三傳["末傳"].支神 = next;
            }
            else
            {
                pan69.三傳["初傳"].支神 = pan69.取上神(pan69.日支);
                String next = GJR.A刑B(pan69.三傳["初傳"].支神);
                if (next.Equals(pan69.三傳["初傳"].支神))
                {
                    next = pan69.取上神(GJR.天干寄宮(日干));
                }
                pan69.三傳["中傳"].支神 = next;
                next = GJR.A刑B(pan69.三傳["中傳"].支神);
                if (next.Equals(pan69.三傳["中傳"].支神) || next.Equals(pan69.三傳["初傳"].支神))
                    next = GJR.沖(pan69.三傳["中傳"].支神);
                pan69.三傳["末傳"].支神 = next;
            }
        }

        private void process八專(BigSixNinePan pan69, List<string> notes)
        {
            bool 陽日 = GJR.陰陽(pan69.日干) == e陰陽.陽;
            if (陽日)
            {
                String up = pan69.取上神(GJR.天干寄宮(pan69.日干));
                pan69.三傳["中傳"].支神 = up;
                pan69.三傳["末傳"].支神 = pan69.三傳["中傳"].支神;
                up = GJR.位移(up, 2);
                pan69.三傳["初傳"].支神 = up;
            }
            else
            {
                //取第四課
                pan69.三傳["初傳"].支神 = GJR.位移(pan69.課[3].上神, -2);
                pan69.三傳["中傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
                pan69.三傳["末傳"].支神 = pan69.三傳["中傳"].支神;
            }
        }

        private void process別責(BigSixNinePan pan69, List<string> notes)
        {
            bool 陽日 = GJR.陰陽(pan69.日干) == e陰陽.陽;
            if (陽日)
            {
                pan69.三傳["初傳"].支神 = pan69.取上神(GJR.天干寄宮(GJR.五合(pan69.日干)));
                pan69.三傳["中傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
                pan69.三傳["末傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
            }
            else
            {
                pan69.三傳["初傳"].支神 = GJR.三合前(pan69.日支);
                pan69.三傳["中傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
                pan69.三傳["末傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
            }

        }

        private void process昂星(BigSixNinePan pan69, List<string> notes)
        {
            bool 陽日 = GJR.陰陽(pan69.日干) == e陰陽.陽;
            if (陽日)
            {
                notes.Add("昂星法 : 剛日");
                pan69.三傳["初傳"].支神 = pan69.取上神("酉");
                pan69.三傳["中傳"].支神 = pan69.取上神(pan69.日支);
                pan69.三傳["末傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日支));
            }
            else
            {
                notes.Add("昂星法 : 柔日");
                pan69.三傳["初傳"].支神 = pan69.取下神("酉");
                pan69.三傳["中傳"].支神 = pan69.取上神(GJR.天干寄宮(pan69.日干));
                pan69.三傳["末傳"].支神 = pan69.取上神(pan69.日支);
            }
        }

        protected bool process基本比用涉害(BigSixNinePan pan69, List<int> classIds, List<string> notes)
        {
            if (classIds.Count == 1)
            {
                processPhase3Basic(pan69, classIds[0]);
                return true;
            }
            if (process比用(pan69, classIds, notes))
                return true;
            return process涉害(pan69, classIds, notes);
        }
        private bool process遙剋(BigSixNinePan pan69, List<string> notes)
        {
            //藁矢 天盤 喀 pan69.日干 
            List<int> 天盤剋日干 = new List<int>();
            List<int> 日干剋天盤 = new List<int>();
            for (int i = 0; i < 4; i++)
            {
                int k = GJR.A剋B(pan69.課[i].上神, pan69.日干);
                if (k > 0)
                    天盤剋日干.Add(i);
                if (k < 0)
                    日干剋天盤.Add(i);
            }
            //-----------------------------------
            if ((天盤剋日干.Count + 日干剋天盤.Count) == 0)
                return false;
            if (天盤剋日干.Count > 0)
            {
                if (process基本比用涉害(pan69, 天盤剋日干, notes))
                    return true;
            }
            if (日干剋天盤.Count > 0)
            {
                if (process基本比用涉害(pan69, 日干剋天盤, notes))
                    return true;
            }
            return false;
        }


        private bool processBasic(BigSixNinePan pan69, List<int> 賊課, List<int> 剋課, List<String> notes, bool basic)
        {
            if (賊課.Count > 0)
            {
                if (賊課.Count == 1)
                {
                    if (剋課.Count == 0)
                    {
                        if (basic)
                            notes.Add("始入課");
                    }
                    else
                    {
                        if (basic)
                            notes.Add("重審課");
                    }
                    int clazzId = 賊課[0];
                    processPhase3Basic(pan69, clazzId);
                    return true;
                }
                else
                {
                    if (process比用(pan69, 賊課, notes))
                        return true;
                    process涉害(pan69, 賊課, notes);
                    return true;
                }
            }
            if (剋課.Count > 0)
            {
                if (剋課.Count == 1)
                {
                    notes.Add("元首課");
                    return processPhase3Basic(pan69, 剋課[0]);
                }
                else
                {
                    if (process比用(pan69, 剋課, notes))
                        return true;
                    process涉害(pan69, 剋課, notes);
                    return true;
                }
            }
            return false;
        }


        private bool process涉害(BigSixNinePan pan69, List<int> 課, List<String> notes)
        {
            int sz = 課.Count;
            int min = 3;
            int minid = -1;
            for (int i = 0; i < sz; i++)
            {
                int clazzId = 課[i];
                if (pan69.課[clazzId].上神孟仲季 < min)
                {
                    min = pan69.課[clazzId].上神孟仲季;
                    minid = clazzId;
                }
            }
            notes.Add("涉害 : 取第" + (minid + 1) + "課 " + pan69.課[minid].柱);
            processPhase3Basic(pan69, minid);
            return true;
        }

        private bool process比用(BigSixNinePan pan69, List<int> 賊課, List<String> note)
        {
            var 日干陰陽 = GJR.陰陽(pan69.日干);
            int sz = 賊課.Count;
            List<int> 比課 = new List<int>();
            for (int i = 0; i < sz; i++)
            {
                int classId = 賊課[i];
                if (GJR.陰陽(pan69.課[i].上神) == 日干陰陽)
                {
                    比課.Add(classId);
                }
            }
            if (比課.Count == 1)
            {
                int id = 比課[0];
                note.Add("比用: 第" + id + "課 " + pan69.課[id].上神 + pan69.課[id].下神);
                processPhase3Basic(pan69, id);
                return true;
            }
            if (比課.Count == 0)
                return false;
            return process涉害(pan69, 比課, note);
        }



        private bool processPhase3Basic(BigSixNinePan pan69, int clazzId)
        {
            String 初傳 = pan69.課[clazzId].上神;
            String 中傳 = pan69.地盤(初傳).天;
            String 末傳 = pan69.地盤(中傳).天;
            pan69.三傳["初傳"].支神 = 初傳;
            pan69.三傳["中傳"].支神 = 中傳;
            pan69.三傳["末傳"].支神 = 末傳;
            return true;
        }

        private List<string> prepare4Class(Pillar4 pillar4, List<Dictionary<string, string>> pan)
        {

            String d_gan = pillar4.dayGj.干;
            String d_ji = pillar4.dayGj.支;

            List<String> result = new List<String>();

            String ji = GJR.天干寄宮(d_gan);
            String upji = pan[GJR.JiId(ji) % 12]["天"];
            result.Add(upji + d_gan);
            ji = upji;
            upji = pan[GJR.JiId(ji) % 12]["天"];
            result.Add(upji + ji);

            ji = d_ji;
            upji = pan[GJR.JiId(ji) % 12]["天"];
            result.Add(upji + ji);

            ji = upji;
            upji = pan[GJR.JiId(ji) % 12]["天"];
            result.Add(upji + ji);
            return result;
        }

        private void prepareSkyGeneral(Pillar4 pillar4, List<Dictionary<string, string>> pan, Dictionary<String, Object> note)
        {
            String dayGan = pillar4.dayGj.干;
            String hrJi = pillar4.hourGj.支;
            bool isday = isDay(hrJi);

            String 晝貴 = GJR.貴人晝占(dayGan);
            String 夜貴 = GJR.貴人夜占(dayGan);

            note.Add("晝貴", 晝貴);
            note.Add("夜貴", 夜貴);

            String skyStart = "";
            if (isday)
                skyStart = 晝貴;
            else
                skyStart = 夜貴;
            //-------------------------------
            bool counter = true;
            String groundStart = "";
            foreach (var item in pan)
            {
                if (item["天"].Equals(skyStart))
                {
                    groundStart = item["地"];
                    counter = isDirCounter(groundStart);
                }
            }
            if(counter)
                note.Add("天將", "順");
            else
                note.Add("天將", "逆");
            //------->
            int gpos = GJR.JiId(groundStart);
            for (int i = 0; i < 12; i++)
            {
                int pos;
                if (counter)
                    pos = ((gpos + i) + 12) % 12;
                else
                    pos = ((gpos - i) + 12) % 12;
                pan[pos].Add("天將", _天將[i]);
            }

        }

        private bool isDirCounter(string groundStart)
        {
            int id = GJR.JiId(groundStart) % 12;
            if (id <= 5)
                return true;
            return false;
        }
        public List<String> createSkyPan(String hrji, String monGeneral)
        {
            int offset = GJR.JiId(monGeneral) - GJR.JiId(hrji);
            if (offset < 0)
                offset += 12;
            List<String> result = new List<string>();
            for (int i = 0; i < 12; i++)
            {
                String ji = GJR.Id2Ji((offset + i) % 12);
                result.Add(ji);
            }
            return result;
        }
        private void prepareSkyPan(Pillar4 pillar4, String monthGeneral, List<Dictionary<String, String>> pan)
        {
            List<String> sky = createSkyPan(pillar4.hourGj.支, monthGeneral);
            for (int i = 0; i < 12; i++)
            {
                pan[i].Add("天", sky[i]);
            }
        }

    }
}
